package com.jsu.forum.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.stat.descriptive.summary.Sum;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.example.model.common.dtos.ResponseResult;
import org.example.model.common.enums.WebHttpCodeEnum;
import org.example.model.forum.dto.SearchDto;
import org.example.model.forum.pojo.Passage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.sql.Date;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

@Service
@Slf4j
public class SearchServiceImpl {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 获取搜索热词
     * @return
     */
    public ResponseResult getHotSearch() {
        List<SearchDto> topKeywords = new ArrayList<>();
        try {
            SearchRequest searchRequest = new SearchRequest("search_keywords");
            searchRequest.source().size(0);

            searchRequest.source().aggregation(
                    AggregationBuilders
                            .terms("top_keywords")
                            .field("keyword")
                            .order(BucketOrder.aggregation("keyword_count", false))
                            .subAggregation(
                                    AggregationBuilders
                                            .sum("keyword_count")
                                            .field("count")
                            )
                            .size(10)
            );

            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            ParsedStringTerms topKeywordsAgg = searchResponse.getAggregations().get("top_keywords");
            for (Terms.Bucket bucket : topKeywordsAgg.getBuckets()) {
                String keyword = bucket.getKeyAsString();
                long count = (long) ((ParsedSum) bucket.getAggregations().get("keyword_count")).getValue();
                topKeywords.add(new SearchDto(count, keyword));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
       if(topKeywords.isEmpty()){
           return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"暂无热词");
       }
       return ResponseResult.okResult(topKeywords);
    }

    /**
     * 获取模糊搜索词条
     * @param keyword
     */
    public ResponseResult searchKeywords(String keyword) {
        indexSearchKeyword(keyword);
        List<String> searchResults = new ArrayList<>();
        // 构建搜索请求
        SearchRequest searchRequest = new SearchRequest("search_keywords");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 构建模糊查询条件
        sourceBuilder.query(QueryBuilders.matchQuery("keyword", keyword));



        searchRequest.source(sourceBuilder);
        // 执行搜索请求
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 处理搜索结果
        SearchHits hits = searchResponse.getHits();
        for (SearchHit hit : hits) {
            // 获取搜索结果中的关键字信息
            String keywordMatched = (String) hit.getSourceAsMap().get("keyword");
            if(!searchResults.contains(keywordMatched))
                searchResults.add(keywordMatched);
        }
        if(searchResults.isEmpty())
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"暂无搜索结果");
        return ResponseResult.okResult(searchResults);
    }

    /**
     * 模糊搜索
     * @param keyword
     * @return
     */
    public ResponseResult searchPassage(String keyword) {
        // 存储搜索关键字到Elasticsearch
        indexSearchKeyword(keyword);
        SearchRequest searchRequest = new SearchRequest("ninesunindex");//里面可以放多个索引
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();//构造搜索条件

        // 构建模糊查询条件
        sourceBuilder.query(QueryBuilders.boolQuery()
                .should(QueryBuilders.matchQuery("content", keyword))
                .should(QueryBuilders.matchQuery("authorName", keyword)));

        // 构建排序条件
        sourceBuilder.sort(SortBuilders.fieldSort("count").order(SortOrder.DESC));
        sourceBuilder.sort(SortBuilders.fieldSort("publishTime").order(SortOrder.DESC));
        sourceBuilder.sort(SortBuilders.fieldSort("score").order(SortOrder.DESC));

        // 设置高亮显示参数
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                .field("content")
                .field("authorName")
                .preTags("<span style='color:red'>")
                .postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 处理搜索结果并返回
            List<Passage> passages = new ArrayList<>();
            SearchHits hits = searchResponse.getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                Passage passage = new Passage();
                passage.setPkId((Integer) sourceAsMap.get("pkId"));
                passage.setContext((String) sourceAsMap.get("context"));
                passage.setImage1((String) sourceAsMap.get("image1"));
                passage.setImage2((String) sourceAsMap.get("image2"));
                passage.setImage3((String) sourceAsMap.get("image3"));
                passage.setImage4((String) sourceAsMap.get("image4"));
                passage.setImage5((String) sourceAsMap.get("image5"));
                passage.setImage6((String) sourceAsMap.get("image6"));
                passage.setAuthorId((Integer) sourceAsMap.get("authorId"));
                passage.setAuthorName((String) sourceAsMap.get("authorName"));
                passage.setPublishTime((Date) sourceAsMap.get("publishTime"));
                passage.setLikeCount((Integer) sourceAsMap.get("likeCount"));
                passage.setCount((Integer) sourceAsMap.get("count"));
                passage.setCommentCount((Integer) sourceAsMap.get("commentCount"));
                passage.setState((String) sourceAsMap.get("state"));
                passage.setScore((Double) sourceAsMap.get("score"));
                // 设置其他字段的值，以此类推
                passages.add(passage);
            }
            return ResponseResult.okResult(passages);
        } catch (IOException e) {
            log.error("出错了: {}", e.getMessage());
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"搜索失败");
        }
    }


    /**
     * 存储搜索关键字到Elasticsearch，如果已存在则增加搜索次数，否则新增一条记录
     * @param keyword 搜索关键字
     */
    private void indexSearchKeyword(String keyword) {
        try {
            // 检查该关键词是否已存在
            GetRequest getRequest = new GetRequest("search_keywords", keyword);
            boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
            if (exists) {
                // 如果关键词已存在，更新搜索次数
                UpdateRequest updateRequest = new UpdateRequest("search_keywords", keyword)
                        .doc(jsonBuilder()
                                .startObject()
                                .field("count", 1)
                                .endObject())
                        .upsert(jsonBuilder()
                                .startObject()
                                .field("keyword", keyword)
                                .field("timestamp", LocalDateTime.now())
                                .field("count", 1)
                                .endObject());
                restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
                log.info("更新搜索次数: {}", keyword);
            } else {
                // 如果关键词不存在，新增一条记录
                IndexRequest indexRequest = new IndexRequest("search_keywords")
                        .source(jsonBuilder()
                                .startObject()
                                .field("keyword", keyword)
                                .field("timestamp", LocalDateTime.now())
                                .field("count", 1)
                                .endObject());
                restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
                log.info("新增搜索记录: {}", keyword);
            }
        } catch (IOException e) {
            log.error("出错了: {}", e.getMessage());
        }
    }

}
